package com.mian.client;

import com.mian.annotation.Reference;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;


// ioc容器所创建的每一个bean在初期化方法前后都会调用
@Component
public class ServiceInstance implements BeanPostProcessor, BeanDefinitionRegistryPostProcessor {

	private ConfigurableListableBeanFactory beanFactory;

	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {


		ReflectionUtils.doWithFields(bean.getClass(), field -> {

			// 被指定注解  注解的field
			Reference annotation = field.getAnnotation(Reference.class);
			if (annotation == null) {
				return;
			}

			// type = com.mian.netty.demo.GreeterGrpc$GreeterBlockingStub
			Class<?> type = field.getType();
			Object oper = null;

			// 有两种方案
			// 第一种方案： 启动的时候，直接扫描 @Reference的的service,实例化，然后扔到 spring容器中，直接从容器中获取
			// 第二种方案： 实例化该bean的时候，此时再实例化 其field->oper，那么，多个controller中引用了同一个service，则分别建立链接
			//  客户端 长连 or 短链的问题，暂时不考虑
			// =====> 直接建立连接 todo 根据 type(service) 从zk上选择一个注册的server(host:port)
			String host = "localhost";
			int port = 50051;

			GrpcClient client = new GrpcClient(host, port);
			oper = client.getBlockingStub(type);

			boolean accessible = field.isAccessible();
			ReflectionUtils.makeAccessible(field);
			field.set(bean, oper);
			field.setAccessible(accessible);
		});
		return bean;

	}


	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

	}

	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;
	}
}
